package icommand.nxt.comm;

import java.util.Properties;

class NXTCommBluez implements NXTComm {

	private static final String BDADDR_ANY = "00:00:00:00:00:00";

	private int sk = -1;

	private String NXTBTAddress;

	static {
		System.loadLibrary("icmdbluez");
	}

	
	public NXTCommBluez() {
	}
	
	public NXTCommBluez(Properties props) {
		NXTBTAddress = props.getProperty(NXTCommFactory.BT_ADDRESS);
	}

	public void setAddress(String address) {		
		NXTBTAddress = address;
	}
			
	public NXTInfo[] search(String name, int protocol) {
		String[] btString = null;
		
		try {
			btString = search(name);
		} catch (BlueZException e) {
			System.err.println(e.getMessage());	
		}
		if (btString == null) return new NXTInfo[0];
		else {
			NXTInfo[] nxts = new NXTInfo[btString.length];
			for(int i=0;i<btString.length;i++) {
				NXTInfo nxtInfo = new NXTInfo();
				if (btString[i] == null) {
					System.err.println("Null btString");
					return new NXTInfo[0];
				}
				int sep = btString[i].indexOf("::");
				//System.out.println("Setting address to " + btAddress);
				nxtInfo.btDeviceAddress =  btString[i].substring(sep+2);
				nxtInfo.name = btString[i].substring(0, sep);
				nxtInfo.protocol = NXTCommFactory.BLUETOOTH;
				nxtInfo.btResourceString = btString[i];
			
				nxts[i] = nxtInfo;			
			}
			return nxts;
		}
	}
	
	public void open() throws BlueZException {
		open(BDADDR_ANY, NXTBTAddress, 1);
	}
	
	public void close() {
		try {
			rcSocketShutdown(sk);
		} catch (BlueZException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
			if (sk != -1) {
				try {
					rcSocketClose(sk);
				} catch (BlueZException e1) {
					System.err.println(e.getMessage());
					e.printStackTrace();
				}
				sk = -1;
			}
		}
	}

	public byte[] readData() {
		byte[] data = null;
		try {
			data = rcSocketRecv(sk);
		} catch (BlueZException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}
		
		// remove lsb & msb
		data = subArray(data, 2, data.length);

		return data;
	}

	public void sendData(byte[] request) {
		
		// add lsb & msb
		byte[] lsb_msb = new byte[2];
		lsb_msb[0] = (byte) request.length;
		lsb_msb[1] = (byte) 0x00;
		request = concat(lsb_msb, request);
	
		try {
			rcSocketSend(sk, request);
		} catch (BlueZException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}
	}

	private void open(String l_bdaddr, String r_bdaddr, int channel) throws BlueZException {
		boolean ok = false;

		try {
			sk = rcSocketCreate();
			rcSocketBind(sk, l_bdaddr);
			rcSocketConnect(sk, r_bdaddr, channel);

			ok = true;
		} finally {
			if (!ok) {
				if (sk != -1) {
					rcSocketClose(sk);
					sk = -1;
				}
			}
		}
	}
	
	private byte[] concat(byte[] data1, byte[] data2) {
		int l1 = data1.length;
		int l2 = data2.length;
		
		byte[] data = new byte[l1 + l2];
		System.arraycopy(data1, 0, data, 0, l1);
		System.arraycopy(data2, 0, data, l1, l2);
		
		return data;
	}
		
	
	private byte[] subArray(byte[] data, int start, int end) {	

		byte[] result = new byte[end - start];
		System.arraycopy(data, start, result, 0, end - start);

		return result;
	}
	
	native private String[] search(String name) throws BlueZException;
	
	native private int rcSocketCreate() throws BlueZException;

	native private void rcSocketBind(int sk, String bdaddr) throws BlueZException;

	native private void rcSocketConnect(int sk, String bdaddr, int channel) throws BlueZException;

	native private void rcSocketSend(int sk, byte[] data) throws BlueZException;

	native private byte[] rcSocketRecv(int sk) throws BlueZException;

	native private void rcSocketShutdown(int sk) throws BlueZException;

	native private void rcSocketClose(int sk) throws BlueZException;
	
}